Skip to main content

DeadmanSwitch Technical Documentation

Overview​

DeadmanSwitch is a Solidity smart contract module designed for account recovery in cases of user inactivity. It implements a safety mechanism allowing a designated nominee to recover access to an account after a specified period of inactivity.

License​

AGPL-3.0-only

Solidity Version​

^0.8.25

Dependencies​

  • modulekit/Modules.sol: ERC7579ValidatorBase, ERC7579HookBase
  • modulekit/ModuleKit.sol: PackedUserOperation
  • solady/utils/SignatureCheckerLib.sol
  • solady/utils/ECDSA.sol

Key Components​

Constants & Storage​

DeadmanSwitchStorage Struct​

struct DeadmanSwitchStorage {
uint48 lastAccess; // Timestamp of the last account activity
uint48 timeout; // Duration after which nominee can take control
address nominee; // Address authorized to recover the account
}

State Variables​

  • mapping(address account => DeadmanSwitchStorage) public config: Maps accounts to their DeadmanSwitch configuration

Events​

  1. ModuleInitialized(address indexed account, address nominee, uint48 timeout)
  2. ModuleUninitialized(address indexed account)
  3. NomineeSet(address indexed account, address nominee)
  4. TimeoutSet(address indexed account, uint48 timeout)

Errors​

  • UnsupportedOperation(): Thrown when attempting unsupported operations
  • AlreadyInitialized(address): Thrown when trying to initialize an already initialized account
  • NotInitialized(address): Thrown when performing operations on an uninitialized account

Core Functionality​

Module Management​

onInstall​

function onInstall(bytes calldata data) external

Initializes the DeadmanSwitch for an account.

  • Data format: abi.encodePacked(nominee, timeout)
  • Nominee: first 20 bytes (address)
  • Timeout: next 6 bytes (uint48)
  • Emits ModuleInitialized event

onUninstall​

function onUninstall(bytes calldata) external

Removes the DeadmanSwitch configuration.

  • Clears all stored data
  • Emits ModuleUninitialized event

isInitialized​

function isInitialized(address smartAccount) public view returns (bool)

Checks if an account has initialized the module.

  • Returns true if nominee is set (non-zero address)

Configuration Functions​

setNominee​

function setNominee(address nominee) external

Updates the nominee address.

  • Requires initialized module
  • Emits NomineeSet event

setTimeout​

function setTimeout(uint48 timeout) external

Updates the timeout duration.

  • Requires initialized module
  • Emits TimeoutSet event

Hook Functions​

_preCheck​

function _preCheck(
address account,
address,
uint256,
bytes calldata
) internal override returns (bytes memory hookData)

Updates last access time before execution.

  • Only updates if module is initialized
  • Returns empty string

_postCheck​

function _postCheck(address, bytes calldata) internal override

Post-execution hook (currently unused).

Validation Functions​

validateUserOp​

function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash
) external override returns (ValidationData)

Validates user operations for account recovery.

  • Checks nominee's signature
  • Verifies timeout period
  • Returns packed validation data:
    • Signature validity
    • Valid after timestamp (timeout)
    • Valid until (max uint48)

isValidSignatureWithSender​

function isValidSignatureWithSender(
address,
bytes32,
bytes calldata
) external pure override returns (bytes4)

ERC-1271 signature validation (unsupported).

  • Always reverts with UnsupportedOperation

Metadata Functions​

isModuleType​

function isModuleType(uint256 typeID) external pure returns (bool)

Identifies supported module types.

  • Returns true for TYPE_HOOK or TYPE_VALIDATOR

name​

function name() external pure virtual returns (string memory)

Returns module name: "DeadmanSwitch"

version​

function version() external pure virtual returns (string memory)

Returns module version: "1.0.0"

Technical Specifications​

  1. Timing Mechanism

    • Uses uint48 for timestamps and timeouts
    • Updates lastAccess on every valid operation
    • Recovery window opens after lastAccess + timeout
  2. Security Features

    • Nominee signature required for recovery
    • ERC-1271 signatures explicitly unsupported
    • Module can be uninstalled by the account owner
  3. Gas Optimization

    • Uses uint48 for timestamps to save storage
    • Implements view functions where possible

Integration Guide​

To integrate this module:

  1. Deploy the DeadmanSwitch contract
  2. Install the module on the target account with:
    bytes memory initData = abi.encodePacked(nomineeAddress, timeoutInSeconds);
    // Call installation method with initData
  3. Ensure the account's validation flow includes this module

Example Usage​

// Installation
bytes memory initData = abi.encodePacked(
address(0x1234...), // nominee
uint48(7 days) // timeout
);
account.installModule(deadmanSwitch, initData);

// Updating nominee
deadmanSwitch.setNominee(newNomineeAddress);

// Updating timeout
deadmanSwitch.setTimeout(uint48(14 days));

Security Considerations​

  1. Recovery Window

    • Nominee can only recover after timeout
    • Each account interaction resets the timer
  2. Access Control

    • Only account owner can change nominee and timeout
    • Only nominee can execute recovery
  3. Limitations

    • No emergency override
    • Timeout period is fixed once set

Best Practices​

  1. Choose an appropriate timeout period
  2. Select a trusted nominee
  3. Regularly verify nominee and timeout settings
  4. Consider backup recovery mechanisms